package pathfinding;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Double;
import java.util.ArrayList;

import base.Geometry;
import base.Ship;

public class GridGeometry {
	// should be >0
	public static final double gridSize = Ship.getLength() / 2.0; 

	public static Point2D.Double getCenter(GridCell c)
	{
		return new Point2D.Double(c.x * gridSize + gridSize/2.0, c.y*gridSize + gridSize/2.0);
	}
	
	public static GridCell getCell(double x, double y) {
		int cellX = (int) (x / gridSize);
		int cellY = (int) (y / gridSize);
		
		if (y < 0)
		{
			cellY -= 1;
		}
		if (x < 0)
		{
			cellX -= 1;
		}
		
		return new GridCell(cellX, cellY);
	}
	
	public static GridCell getCell(Ship s) {
		return GridGeometry.getCell(s.getX(), s.getY());
	}
	
	public static ArrayList<GridCell> getCells(Ship s)
	{
		ArrayList<GridCell> result = new ArrayList<GridCell>();
		
		Point2D.Double [] rect = s.getRect();
		
		Point2D.Double min = Geometry.getMin(rect);
		Point2D.Double max = Geometry.getMax(rect);
		
		// create a grid of width x height GridCells
		GridCell upperLeft = GridGeometry.getCell(min.x, max.y);
		GridCell lowerRight = GridGeometry.getCell(max.x, min.y);
		
		ArrayList<GridCell> candidates = new ArrayList<GridCell>();
		
		for (int x = upperLeft.x; x <= lowerRight.x; x++)
		{
			for (int y = lowerRight.y; y <= upperLeft.y; y++)
			{
				candidates.add(new GridCell(x,y));
			}
		}
		
		Line2D.Double[] lines = Geometry.getRectLines(rect);
		
		for (GridCell c : candidates) {
			Rectangle2D.Double r = GridGeometry.getRectangle(c);
			for (Line2D.Double line : lines)
			{
				if (r.intersectsLine(line)) {
					result.add(c);
					break; // break the inner loop (to avoid duplicates)
				}
			}
		}
		
		return result;
	}
	
	public static Rectangle2D.Double getRectangle(GridCell c)
	{
		return new Rectangle2D.Double (c.x * GridGeometry.gridSize, 
				                       c.y * GridGeometry.gridSize, 
				                       GridGeometry.gridSize,
				                       GridGeometry.gridSize);
	}
	
	/**
	 * Returns true iff the given cell is equal to a cell that would be created from given coordinates
	 * @param a
	 * @param x
	 * @param y
	 * @return
	 */
	public static boolean equalCells(GridCell a, double x, double y)
	{
		if (a == null) {
			return false;
		}
		int cellX = (int) (x / gridSize);
		int cellY = (int) (y / gridSize);
		
		if (y < 0)
		{
			cellY -= 1;
		}
		if (x < 0)
		{
			cellX -= 1;
		}
		
		return (a.x == cellX && a.y == cellY);
	}
	
	public static int manhattanDist(GridCell a, GridCell b)
	{
		return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
	}
	
	public static int amountOfSquaresBetween(GridCell a, GridCell b)
	{
		return Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y));
	}
	
	protected static boolean isDiagonalNeighbour(GridCell from, GridCell to) {
		if (GridGeometry.manhattanDist(from, to) != 2) {
			return false;
		}
		if (from.x == to.x || from.y == to.y) {
			return false;
		}
		
		return true;
	}
}
